//imports
<?php
$l_classesToImport=array();
$l_foreignKeyFields=array_keys($l_tableStructure->foreignKeys);
foreach($l_foreignKeyFields as $l_foreignKeyField){
	$l_classesToImport[]=ucfirst($l_tableStructure->foreignKeys[$l_foreignKeyField]);
}
foreach($l_tableStructure->childKeys as $l_childKey){
	$l_classesToImport[]=ucfirst($l_childKey->tableName);
}


$l_classesToImport=array_unique($l_classesToImport);
foreach($l_classesToImport as $l_classToImport){
	?>
require_once("<?=$l_classToImport ?>.php");
	<?php
}
?>

class <?=$l_className ?>_DAO{
	//Variables
	<?php
	$l_fieldNames=array_keys($l_tableStructure->fields);
	foreach($l_fieldNames as $l_fieldName){
	?>
	private $<?=$l_fieldName ?>;
	<?php
	}
	?>	

	//Accessors
	<?php
	foreach($l_fieldNames as $l_fieldName){
		$l_accessorName=ucfirst($l_fieldName);
	?>
	
	public function get<?=$l_accessorName ?>(){
		return $this-><?=$l_fieldName ?>;
	}
	
	public function set<?=$l_accessorName ?>($p_<?=$l_fieldName ?>){
		$this-><?=$l_fieldName ?>=$p_<?=$l_fieldName ?>;
	}
	<?php
	}
	?>	
	
	//Accessors for foreignKeys
	<?php
	$l_foreignKeyFields=array_keys($l_tableStructure->foreignKeys);
	foreach($l_foreignKeyFields as $l_foreignKeyField){
		$l_accessorName=ucfirst($l_foreignKeyField);
		$l_referencedClassName=ucfirst($l_tableStructure->foreignKeys[$l_foreignKeyField]);
	?>
	public function get<?=$l_accessorName ?>_Ref(){
		return <?= $l_referencedClassName ?>::getFromPrimaryKey($this->get<?=$l_accessorName ?>());
	}
	<?php
	}
	?>	
	
	//Method to get referenced objects
	<?php
	//$l_childKeysFields=array_keys($l_tableStructure->childKeys);
	//foreach($l_childKeysFields as $l_childKeysField){
	foreach($l_tableStructure->childKeys as $l_childKey){
		$l_accessorName=ucfirst($l_childKey->columnName);
		$l_methodName=ucfirst($l_childKey->accessor);
		$l_childClassName=ucfirst($l_childKey->tableName);
		?>
	public function get<?=$l_methodName ?>s(){
		return <?= $l_childClassName ?>::getFromCustomCriteria("WHERE <?=$l_accessorName ?>=:value",array("value" => $this->get<?=ucfirst($l_tableStructure->primaryKeyFieldName) ?>()));
	}
		<?php
	}
	?>
	
	/**
	 * Attempt an INSERT if the primary key is empty, otherwise perform an UPDATE.
	 * @param boolean $p_forceCreation true if save must trigger a create (by-pass the automatic ID generation) 
	 */
	public function save($p_forceCreation=false){
		try {
			$l_dbh = new PDO(__DB_URL, __DB_USER, __DB_PASSWORD);
			
			<?php
				$l_primaryKeyAccessorName=ucfirst($l_tableStructure->primaryKeyFieldName);
			?>
			$l_hasKey=$this->get<?=$l_primaryKeyAccessorName ?>();
			if(!isset($l_hasKey) || $p_forceCreation){
				//Attempt an INSERT
				if(!$p_forceCreation){
					$this->set<?=$l_primaryKeyAccessorName ?>(strval(uniqid("W-", true)) . "-" . strval(rand(100000,999999)));
				}
				<?php
					$l_fields=implode(",",$l_fieldNames);
					$l_values=implode(",:",$l_fieldNames);
					$l_values=":{$l_values}";
					$l_sql="INSERT INTO {$p_tableName} ($l_fields) VALUES ($l_values)";
				?>
				$l_sth = $l_dbh->prepare("<?=$l_sql ?>");
				<?php
				foreach($l_fieldNames as $l_fieldName){
					$l_accessorName=ucfirst($l_fieldName);
				?>
					modifiedBindParam($l_sth,':<?=$l_fieldName ?>',$this->get<?=$l_accessorName ?>());
				<?php
				}
				?>
				if(!$l_sth->execute()){
					throw new PDOException(implode(" - ",$l_sth->errorInfo()));
				}
			}else{
				//Attempt an UPDATE
				<?php
					$l_settersArray=array();
					foreach($l_fieldNames as $l_fieldName){
						if($l_fieldName!=$l_tableStructure->primaryKeyFieldName){
							$l_settersArray[]="{$l_fieldName}=:{$l_fieldName}";
						}
					}
					$l_setters=implode(", ",$l_settersArray);
					$l_whereClause="{$l_tableStructure->primaryKeyFieldName}=:{$l_tableStructure->primaryKeyFieldName}";
					$l_sql="UPDATE {$p_tableName} SET $l_setters WHERE $l_whereClause";
				?>
				$l_sth = $l_dbh->prepare("<?=$l_sql ?>");
				<?php
				foreach($l_fieldNames as $l_fieldName){
					$l_accessorName=ucfirst($l_fieldName);
				?>
					modifiedBindParam($l_sth,':<?=$l_fieldName ?>',$this->get<?=$l_accessorName ?>());
				<?php
				}
				?>
				if(!$l_sth->execute()){
					throw new PDOException(implode(" - ",$l_sth->errorInfo()));
				}				
			}
			
			$l_dbh = null;
		} catch (PDOException $e) {
			print "Error ! : " . $e->getMessage() . "<br/>";
			die();
		}
	}
	
	/**
	 * Delete the current record from the database
	 */
	public function delete(){
		try {
			$l_dbh = new PDO(__DB_URL, __DB_USER, __DB_PASSWORD);
			<?php
			$l_primaryKeyAccessorName=ucfirst($l_tableStructure->primaryKeyFieldName);
			?>
			$l_sth = $l_dbh->prepare("DELETE FROM <?=$p_tableName ?> WHERE <?=$l_tableStructure->primaryKeyFieldName ?>=:value");
			modifiedBindParam($l_sth,':value', $this->get<?=$l_primaryKeyAccessorName ?>());
			if(!$l_sth->execute()){
				throw new PDOException(implode(" - ",$l_sth->errorInfo()));
			}
			//Set the primaryKey to null so that the object might be saved again (=created again)
			$this->set<?=$l_primaryKeyAccessorName ?>(null);
		} catch (PDOException $e) {
			print "Error ! : " . $e->getMessage() . "<br/>";
			die();
		}	
	}
	
	
	/**
	 * Return all the objects from the table
	 */
	public static function getAll(){
		try {
			$l_results=array();
			$l_dbh = new PDO(__DB_URL, __DB_USER, __DB_PASSWORD);
			foreach ($l_dbh->query("SELECT * FROM <?=$p_tableName ?>") as $l_row) {
				$l_object=new <?=$l_className ?>();
				<?php
				foreach($l_fieldNames as $l_fieldName){
					$l_accessorName=ucfirst($l_fieldName);
				?>
				$l_object->set<?=$l_accessorName ?>($l_row['<?=$l_fieldName ?>']);
				<?php
				}
				?>
				$l_results[$l_row['<?=$l_tableStructure->primaryKeyFieldName ?>']]=$l_object;
			}
			$l_dbh = null;
			return $l_results;
		} catch (PDOException $e) {
			print "Error ! : " . $e->getMessage() . "<br/>";
			die();
		}
	}
	
	/**
	 * Return the object identified by the specified key
	 * @param unknown_type $p_id the primary key value
	 */
	public static function getFromPrimaryKey($p_id){
		try {
			$l_dbh = new PDO(__DB_URL, __DB_USER, __DB_PASSWORD);
			$l_sth = $l_dbh->prepare("SELECT * FROM <?=$p_tableName ?> WHERE <?=$l_tableStructure->primaryKeyFieldName ?>=:value");
			modifiedBindParam($l_sth,':value', $p_id);
			if(!$l_sth->execute()){
				throw new PDOException(implode(" - ",$l_sth->errorInfo()));
			}
			
			$l_row=$l_sth->fetch(PDO::FETCH_ASSOC);
			if($l_row){
				$l_object=new <?=$l_className ?>();
				<?php
				foreach($l_fieldNames as $l_fieldName){
					$l_accessorName=ucfirst($l_fieldName);
				?>
				$l_object->set<?=$l_accessorName ?>($l_row['<?=$l_fieldName ?>']);
				<?php
				}
				?>
			}
			$l_dbh = null;
			return $l_object;
		} catch (PDOException $e) {
			print "Error ! : " . $e->getMessage() . "<br/>";
			die();
		}
	}
	
	/**
	 * Return the objects matching the specified SQL SEARCH CLAUSE<br>
	 * WARNING the search is based upon a preparedStatement.<br>
	 * @param string $p_selectionClause a SQL SEARCH CLAUSE (example: WHERE id=:idparam)
	 * @param array $p_arrayOfParameters an array of associations like (param to bind, bind value)
	 */
	public static function getFromCustomCriteria($p_selectionClause, $p_arrayOfParameters){
		try {
			$l_dbh = new PDO(__DB_URL, __DB_USER, __DB_PASSWORD);
			$l_sth = $l_dbh->prepare("SELECT * FROM <?=$p_tableName ?> {$p_selectionClause}");
			
			$l_parameters=array_keys($p_arrayOfParameters);
			foreach($l_parameters as $l_parameter){
				modifiedBindParam($l_sth,$l_parameter, $p_arrayOfParameters[$l_parameter]);
			}
			
			if(!$l_sth->execute()){
				throw new PDOException(implode(" - ",$l_sth->errorInfo()));
			}
			
			$l_rows=$l_sth->fetchAll(PDO::FETCH_ASSOC);
			$l_results=array();
			
			foreach($l_rows as $l_row) {
				$l_object=new <?=$l_className ?>();
				<?php
				foreach($l_fieldNames as $l_fieldName){
					$l_accessorName=ucfirst($l_fieldName);
				?>
				$l_object->set<?=$l_accessorName ?>($l_row['<?=$l_fieldName ?>']);
				<?php
				}
				?>
				$l_results[$l_row['<?=$l_tableStructure->primaryKeyFieldName ?>']]=$l_object;
			}
			$l_dbh = null;
			return $l_results;
		} catch (PDOException $e) {
			print "Error ! : " . $e->getMessage() . "<br/>";
			die();
		}
	}
	
	
	/**
	 * Return the number of objects matching the specified SQL SEARCH CLAUSE<br>
	 * WARNING the search is based upon a preparedStatement.<br>
	 * @param string $p_selectionClause a SQL SEARCH CLAUSE (example: WHERE id=:idparam)
	 * @param array $p_arrayOfParameters an array of associations like (param to bind, bind value)
	 */
	public static function getCustomCount($p_selectionClause, $p_arrayOfParameters){
		try {
			$l_dbh = new PDO(__DB_URL, __DB_USER, __DB_PASSWORD);
			$l_sth = $l_dbh->prepare("SELECT COUNT(*) as count FROM <?=$p_tableName ?> {$p_selectionClause}");
			
			$l_parameters=array_keys($p_arrayOfParameters);
			foreach($l_parameters as $l_parameter){
				modifiedBindParam($l_sth,$l_parameter, $p_arrayOfParameters[$l_parameter]);
			}
			
			if(!$l_sth->execute()){
				throw new PDOException(implode(" - ",$l_sth->errorInfo()));
			}
			
			$l_row=$l_sth->fetch(PDO::FETCH_ASSOC);
			$l_dbh = null;
			if($l_row){
				return $l_row["count"];
			}else{
				die();
			}
		} catch (PDOException $e) {
			print "Error ! : " . $e->getMessage() . "<br/>";
			die();
		}
	}
	
	
	/**
	 * Return the number of objects<br>
	 */
	public static function getCount(){
		return <?=$l_className ?>::getCustomCount("",array()); 
	}
}